Coverage Report

Created: 2024-12-26 12:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
D:\a\tools.proto\tools.proto\compiler\src\gen\base\structure.rs
Line
Count
Source
1
// Copyright (c) 2024, BlockProject 3D
2
//
3
// All rights reserved.
4
//
5
// Redistribution and use in source and binary forms, with or without modification,
6
// are permitted provided that the following conditions are met:
7
//
8
//     * Redistributions of source code must retain the above copyright notice,
9
//       this list of conditions and the following disclaimer.
10
//     * Redistributions in binary form must reproduce the above copyright notice,
11
//       this list of conditions and the following disclaimer in the documentation
12
//       and/or other materials provided with the distribution.
13
//     * Neither the name of BlockProject 3D nor the names of its contributors
14
//       may be used to endorse or promote products derived from this software
15
//       without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
use crate::compiler::structure::{Field, FieldRaw, FieldType, FieldView, FixedField, FixedFieldType, Structure};
30
use crate::compiler::util::types::TypeMapper;
31
use crate::gen::base::map::TypePathMapper;
32
use crate::gen::template::hook::{Render, TemplateHooks};
33
use crate::gen::template::{Scope, Template};
34
use crate::model::protocol::{Description, Endianness};
35
use itertools::Itertools;
36
use std::borrow::Cow;
37
38
pub trait Utilities {
39
    fn get_field_type(field_type: FixedFieldType) -> &'static str;
40
    fn get_fragment_name(field: &Field) -> &'static str;
41
    fn get_bit_codec_inline(endianness: Endianness) -> &'static str;
42
    fn get_byte_codec_inline(endianness: Endianness) -> &'static str;
43
    fn get_byte_codec(endianness: Endianness) -> &'static str;
44
0
    fn gen_description(desc: &Description) -> Cow<str> {
45
0
        match desc {
46
0
            Description::Single(v) => Cow::Borrowed(v),
47
0
            Description::Multi(v) => Cow::Owned(v.join(" ")),
48
        }
49
0
    }
50
}
51
52
enum Mode {
53
    Getter,
54
    Setter,
55
}
56
57
impl Mode {
58
800
    pub fn get_path<'a>(&self, getter: &'a str, setter: &'a str) -> &'a str {
59
800
        match self {
60
400
            Mode::Getter => getter,
61
400
            Mode::Setter => setter,
62
        }
63
800
    }
64
}
65
66
708
fn gen_structure_field_prologue<'a, 'fragment, 'variable: 'fragment, U: Utilities>(
67
708
    template: &'variable Template<'fragment, 'variable>,
68
708
    field: &'variable Field,
69
708
) -> Scope<'a, 'fragment, 'variable> {
70
708
    let mut scope = template.scope();
71
708
    scope
72
708
        .var_d("start", field.loc.byte_offset)
73
708
        .var_d("end", field.loc.byte_offset + field.loc.byte_size)
74
708
        .var("name", &field.name)
75
708
        .var(
76
708
            "description",
77
708
            field.description.as_ref().map(U::gen_description).unwrap_or("".into()),
78
708
        )
79
708
        .var_d("info", field);
80
708
    scope
81
708
}
82
83
472
fn gen_structure_field<U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>(
84
472
    mode: Mode,
85
472
    field: &Field,
86
472
    template: &Template,
87
472
    field_generator: &mut G,
88
472
) -> Option<String> {
89
472
    let mut scope = gen_structure_field_prologue::<U>(template, field);
90
472
    match &field.ty {
91
400
        FieldType::Fixed(v) => {
92
400
            let bits_type = U::get_field_type(v.bits_type);
93
400
            let raw_type = U::get_field_type(v.raw_type);
94
400
            scope
95
400
                .var("bits_type", bits_type)
96
400
                .var("raw_type", raw_type)
97
400
                .var_d("bit_offset", field.loc.bit_offset)
98
400
                .var_d("bit_size", field.loc.bit_size);
99
400
            Some(field_generator(mode, field, v, scope))
100
        }
101
72
        _ => None,
102
    }
103
472
}
104
105
120
fn gen_structure<'variable, U: Utilities, G: FnMut(Mode, &Field, &FixedField, Scope) -> String>(
106
120
    s: &'variable Structure,
107
120
    mut template: Template<'_, 'variable>,
108
120
    mut field_generator: G,
109
120
) -> String {
110
120
    template.var("struct_name", &s.name).var(
111
120
        "struct_description",
112
120
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
113
120
    );
114
120
    let getters = s
115
120
        .fields
116
120
        .iter()
117
236
        .filter_map(|v| gen_structure_field::<U, G>(Mode::Getter, v, &template, &mut field_generator))
118
120
        .join("");
119
120
    let setters = s
120
120
        .fields
121
120
        .iter()
122
236
        .filter_map(|v| gen_structure_field::<U, G>(Mode::Setter, v, &template, &mut field_generator))
123
120
        .join("");
124
120
    let mut code = template.render("", &["decl"]).unwrap();
125
120
    if !getters.is_empty() {
  Branch (125:8): [True: 54, False: 6]
  Branch (125:8): [True: 54, False: 6]
  Branch (125:8): [True: 0, False: 0]
  Branch (125:8): [True: 0, False: 0]
  Branch (125:8): [Folded - Ignored]
126
108
        code += &template.var("fields", getters).render("", &["getters"]).unwrap();
127
108
    
}12
128
120
    if !setters.is_empty() {
  Branch (128:8): [True: 54, False: 6]
  Branch (128:8): [True: 54, False: 6]
  Branch (128:8): [True: 0, False: 0]
  Branch (128:8): [True: 0, False: 0]
  Branch (128:8): [Folded - Ignored]
129
108
        code += &template.var("fields", setters).render("", &["setters"]).unwrap();
130
108
    
}12
131
120
    code
132
120
}
133
134
200
fn gen_field_raw<'variable>(
135
200
    mode: Mode,
136
200
    _: &'variable Field,
137
200
    fixed: &'variable FixedField,
138
200
    mut scope: Scope<'_, '_, 'variable>,
139
200
) -> String {
140
200
    let path = mode.get_path("getters.field", "setters.field");
141
200
    match &fixed.raw {
142
        FieldRaw::Transmute => {
143
72
            if fixed.raw_type == FixedFieldType::Bool {
  Branch (143:16): [True: 24, False: 48]
  Branch (143:16): [Folded - Ignored]
144
24
                scope.render_to_var(path, &["transmute_bool"], "fragment").unwrap()
145
            } else {
146
48
                scope.render_to_var(path, &["transmute_other"], "fragment").unwrap()
147
            }
148
        }
149
20
        FieldRaw::SignedCast(max_positive) => {
150
20
            scope.var_d("max_positive", max_positive).render_to_var(path, &["signed"], "fragment").unwrap()
151
        }
152
108
        FieldRaw::None => scope.render_to_var(path, &["none"], "fragment").unwrap(),
153
    };
154
200
    scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap()
155
200
}
156
157
200
fn gen_field_bin<'variable, U: Utilities>(
158
200
    mode: Mode,
159
200
    field: &'variable Field,
160
200
    fixed: &'variable FixedField,
161
200
    mut scope: Scope<'_, '_, 'variable>,
162
200
) -> String {
163
200
    let fragment_name = U::get_fragment_name(field);
164
200
    if field.loc.bit_size % 8 != 0 {
  Branch (164:8): [True: 64, False: 136]
  Branch (164:8): [True: 0, False: 0]
  Branch (164:8): [Folded - Ignored]
165
64
        let path = mode.get_path("getters.field.bit", "setters.field.bit");
166
64
        scope
167
64
            .var("codec", U::get_bit_codec_inline(fixed.endianness))
168
64
            .render_to_var(path, &[fragment_name], "fragment")
169
64
            .unwrap();
170
136
    } else {
171
136
        let path = mode.get_path("getters.field.byte", "setters.field.byte");
172
136
        scope
173
136
            .var("codec", U::get_byte_codec_inline(fixed.endianness))
174
136
            .render_to_var(path, &[fragment_name], "fragment")
175
136
            .unwrap();
176
136
    }
177
200
    scope.render(mode.get_path("getters", "setters"), &["field"]).unwrap()
178
200
}
179
180
118
fn gen_field_getter<U: Utilities, T: TypeMapper>(
181
118
    field: &Field,
182
118
    template: &Template,
183
118
    type_path_map: &TypePathMapper<T>,
184
118
) -> String {
185
118
    let mut scope = gen_structure_field_prologue::<U>(template, field);
186
118
    match &field.ty {
187
100
        FieldType::Fixed(v) => gen_field_view_getter::<U, T>(v, &scope, type_path_map),
188
6
        FieldType::Array(v) => scope
189
6
            .var("raw_type", U::get_field_type(v.ty))
190
6
            .var("codec", U::get_byte_codec(v.endianness))
191
6
            .var_d("bit_size", v.item_bit_size)
192
6
            .render("getters", &["array"])
193
6
            .unwrap(),
194
12
        FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("getters", &["struct"]).unwrap(),
195
    }
196
118
}
197
198
118
fn gen_field_setter<U: Utilities, T: TypeMapper>(
199
118
    field: &Field,
200
118
    template: &Template,
201
118
    type_path_map: &TypePathMapper<T>,
202
118
) -> String {
203
118
    let mut scope = gen_structure_field_prologue::<U>(template, field);
204
118
    match &field.ty {
205
100
        FieldType::Fixed(v) => gen_field_view_setter::<U, T>(v, &scope, type_path_map),
206
6
        FieldType::Array(v) => scope
207
6
            .var("raw_type", U::get_field_type(v.ty))
208
6
            .var("codec", U::get_byte_codec(v.endianness))
209
6
            .var_d("bit_size", v.item_bit_size)
210
6
            .render("setters", &["array"])
211
6
            .unwrap(),
212
12
        FieldType::Struct(v) => scope.var("type_name", type_path_map.get(v)).render("setters", &["struct"]).unwrap(),
213
    }
214
118
}
215
216
100
fn gen_field_view_getter<U: Utilities, T: TypeMapper>(
217
100
    field: &FixedField,
218
100
    scope: &Scope,
219
100
    type_path_map: &TypePathMapper<T>,
220
100
) -> String {
221
100
    let mut scope = scope.clone();
222
100
    scope.var("raw_type", U::get_field_type(field.raw_type));
223
100
    match &field.view {
224
4
        FieldView::Float { a, b, .. } => scope
225
4
            .var("view_type", U::get_field_type(field.view_type))
226
4
            .var("a", format!("{:?}", a))
227
4
            .var("b", format!("{:?}", b))
228
4
            .render("getters", &["view_float"])
229
4
            .unwrap(),
230
6
        FieldView::Enum(r) => scope
231
6
            .var("view_type", type_path_map.get(r))
232
6
            .var("repr_type", U::get_field_type(r.repr_type))
233
6
            .render("getters", &["view_enum"])
234
6
            .unwrap(),
235
90
        FieldView::None => scope
236
90
            .var("view_type", U::get_field_type(field.view_type))
237
90
            .render("getters", &["view_none"])
238
90
            .unwrap(),
239
    }
240
100
}
241
242
100
fn gen_field_view_setter<U: Utilities, T: TypeMapper>(
243
100
    field: &FixedField,
244
100
    scope: &Scope,
245
100
    type_path_map: &TypePathMapper<T>,
246
100
) -> String {
247
100
    let mut scope = scope.clone();
248
100
    scope.var("raw_type", U::get_field_type(field.raw_type));
249
100
    match &field.view {
250
4
        FieldView::Float { a_inv, b_inv, .. } => scope
251
4
            .var("view_type", U::get_field_type(field.view_type))
252
4
            .var("a_inv", format!("{:?}", a_inv))
253
4
            .var("b_inv", format!("{:?}", b_inv))
254
4
            .render("setters", &["view_float"])
255
4
            .unwrap(),
256
6
        FieldView::Enum(r) => scope
257
6
            .var("view_type", type_path_map.get(r))
258
6
            .var("repr_type", U::get_field_type(r.repr_type))
259
6
            .render("setters", &["view_enum"])
260
6
            .unwrap(),
261
90
        FieldView::None => scope
262
90
            .var("view_type", U::get_field_type(field.view_type))
263
90
            .render("setters", &["view_none"])
264
90
            .unwrap(),
265
    }
266
100
}
267
268
60
fn gen_structure_getters<U: Utilities, T: TypeMapper>(
269
60
    s: &Structure,
270
60
    template: &Template,
271
60
    type_path_map: &TypePathMapper<T>,
272
60
) -> String {
273
60
    let mut scope = template.scope();
274
118
    let fields = s.fields.iter().map(|v| gen_field_getter::<U, T>(v, template, type_path_map)).join("");
275
60
    scope.var("fields", fields).render("", &["getters"]).unwrap()
276
60
}
277
278
60
fn gen_structure_setters<U: Utilities, T: TypeMapper>(
279
60
    s: &Structure,
280
60
    template: &Template,
281
60
    type_path_map: &TypePathMapper<T>,
282
60
) -> String {
283
60
    let mut scope = template.scope();
284
118
    let fields = s.fields.iter().map(|v| gen_field_setter::<U, T>(v, template, type_path_map)).join("");
285
60
    scope.var("fields", fields).render("", &["setters"]).unwrap()
286
60
}
287
288
pub struct Templates<'fragment, 'variable> {
289
    pub field_template: Template<'fragment, 'variable>,
290
    pub template: Template<'fragment, 'variable>,
291
    pub bits_template: Template<'fragment, 'variable>,
292
    pub raw_template: Template<'fragment, 'variable>,
293
}
294
295
60
pub fn generate<'variable, U: Utilities, T: TypeMapper>(
296
60
    templates: Templates<'_, 'variable>,
297
60
    s: &'variable Structure,
298
60
    type_path_map: &TypePathMapper<T>,
299
60
    hooks: &TemplateHooks,
300
60
) -> String {
301
60
    let mut template = templates.template;
302
60
    let mut field_template = templates.field_template;
303
60
    field_template.var("struct_name", &s.name).var(
304
60
        "struct_description",
305
60
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
306
60
    );
307
60
    template.var("name", &s.name).var_d("byte_size", s.byte_size).var(
308
60
        "struct_description",
309
60
        s.description.as_ref().map(U::gen_description).unwrap_or("".into()),
310
60
    );
311
60
    let mut code = template.render("", &["decl", "new", "fixed_size", "write_to", "from_bytes"]).unwrap();
312
60
    for 
frag26
in hooks.get_fragments("ext") {
313
26
        code += &template.render_frag(frag).unwrap();
314
26
    }
315
60
    code += &gen_structure_getters::<U, T>(s, &field_template, type_path_map);
316
60
    code += &gen_structure_setters::<U, T>(s, &field_template, type_path_map);
317
200
    code += &gen_structure::<U, _>(s, templates.bits_template, |mode, field, fixed, scope| {
318
200
        gen_field_bin::<U>(mode, field, fixed, scope)
319
200
    });
320
200
    code += &gen_structure::<U, _>(s, templates.raw_template, |mode, field, fixed, scope| {
321
200
        gen_field_raw(mode, field, fixed, scope)
322
200
    });
323
60
    code
324
60
}